namespace t0431 {
  interface ICommand {
    executeLevel: number;
    /**
     * 返回true意味着被暂停执行，通常是由于超时
     * 返回false意味着命令在tick时间内执行完了，可以执行下一个命令
     */
    execute(): boolean;
  }
  // Command
  class Draw01Command implements ICommand {
    executeLevel: number = 0; //一般0，每帧结束时要执行的1，每帧都要执行的2
    receiver: Gpu;
    /**
     * 毫秒记执行用时
     */
    timeCost: number;
    constructor(re: Gpu) {
      this.receiver = re;
      this.timeCost = Math.round(Math.random() * 10) * 100;
    }
    execute() {
      this.receiver.on();
      return false;
    }
  }

  // received
  class Gpu {
    on() {
      console.log(`开灯`);
    }
  }

  /**
   * 单个命令的参数
   */
  class SingleParam {
    [k: string]: any;
  }
  /**
   * 核心命令控制类
   */
  class RenderCommandSystem {
    /**
     * 命令列表可用状态，本帧没执行过
     */
    cmdListActive!: boolean;
    /**
     * 关键的命令列表
     */
    cmdList: Array<ICommand> = [];
    cmdListLength!: number;
    /**
     * 当前渲染命令的索引
     */
    cmdIndex!: number;
    /**
     * 关键的命令列表的参数
     */
    paramList!: Array<SingleParam>;
    /**
     * 帧预算用时
     */
    frameBudget!: number;

    lastBeginFrameTimeStamp!: number;
    tickCount!: number;
    /**
     * 本帧用于执行渲染命令的时间
     */
    frameRemaining!: number;
    /**
     * 当前帧是否可以继续执行正常等级的渲染命令
     */
    continueExecution!: boolean;

    /**
     * 标记是否有高等级命令 特权命令
     */
    encounteredAlwaysDo: boolean = false;
    readonly CMD_ALWAYS_DO = 2;
    readonly CMD_DO_AFTER = 1;
    readonly CMD_NORMAL_SEQUENCE = 0;
    /**
     * 记录当前被中止的命令序号
     */
    restartIdx!: number;
    /**
     * 关键函数
     *
     * 准备工作
     * 记录命令
     * 记录参数
     * 标记是否有高等级命令encounteredAlwaysDo
     * @param cmd
     */
    setCommand(cmd: ICommand) {
      this.cmdList.push(cmd);
    }
    /**
     * 虚假的执行函数
     */
    renderThisFrame() {
      for (const iterator of this.cmdList) {
        iterator.execute();
      }
    }
    /**
     * 真实的执行函数
     * @returns 是否执行完，false意味着没执行完，需要下一帧
     */
    executeCommandList(): boolean {
      if (!this.cmdListActive) {
        this.lastBeginFrameTimeStamp = 0;
        return true;
      }
      // 这个与0的判断好像只是为了区分第一次？
      if (this.tickCount > 0) this.lastBeginFrameTimeStamp = 0;
      this.frameRemaining = this.frameBudget;
      this.continueExecution = true;

      if (this.encounteredAlwaysDo) {
        var idx = 0;
        while (idx < this.cmdIndex) {
          if (this.paramList[idx].executionLevel >= this.CMD_ALWAYS_DO) {
            this.cmdList[idx].execute(); // 这个命令插队执行
          }
          idx++;
        }
      }
      /**
       * 从头扫到尾，
       * 若是可以执行就执行，
       * 若是可以执行但执行中止就记录，
       * 若是不继续执行就看看是不是有特权命令要执行
       */
      while (this.cmdIndex < this.cmdListLength) {
        if (this.continueExecution || this.paramList[this.cmdIndex].executionLevel >= this.CMD_DO_AFTER) {
          if (this.cmdList[this.cmdIndex].execute()) {
            // so restart execution at this command the next tick()
            this.restartIdx = this.cmdIndex;
            this.continueExecution = false;
          }
        }
        this.cmdIndex++;
      }
      if (this.continueExecution) {
        //执行完所有命令，时间没用完？
        this.cmdListActive = false;
      } else {
        //中断了执行
        this.cmdIndex = this.restartIdx;
      }
      this.tickCount++;

      // 可以继续执行=没有执行完；不继续执行=执行完了
      return !this.continueExecution;
    }
    isActive(): boolean {
      return this.cmdListActive;
    }
    setFrame(frameBudget: number) {
      this.frameBudget = frameBudget;
    }
    beginCommandSet() {
      //   this.beginCommandSet = function () {
      //   this.cmdListActive = true;
      //   this.cmdIndex = 0;
      //   this.cmdListLength = 0;
      //   this.encounteredAlwaysDo = false;
      //   this.tickCount = 0;
      //   this.screenDrawn = _screenDrawnFlags.NOTHING_DRAWN;
      //   this.screenHasChanged = false;
      // };
    }
    endCommandSet() {
      // this.endCommandSet = function () {
      //   if (this.cmdIsOpen) {
      //     this.cmdIsOpen = false;
      //     // close previous command - really, increment just to get the final count
      //     // 从当前命令序号 蜕变成 真正的列表长度
      //     this.cmdListLength++;
      //   }
      // };
    }
    setParam(indexString: string, val: any) {
      // this.setParam = function (indexString, val) {
      //   if (this.cmdIsOpen) {
      //     this.paramList[this.cmdListLength][indexString] = val;
      //   } else {
      //     if (ENABLE_DEBUG) {
      //       logger.error('ERROR: cannot set param when no command is open!');
      //     }
      //   }
      // };
    }
    getParam(indexString: string) {
      // this.getParam = function (indexString) {
      //   if (ENABLE_DEBUG) {
      //     if (this.paramList[this.cmdIndex][indexString] === undefined) {
      //       logger.error('ERROR: parameter ' + indexString + ' was never set for this command! Go fix it.');
      //     }
      //   }
      //   return this.paramList[this.cmdIndex][indexString];
      // };
    }
  }

  // 新建控制器
  let jjsSystem = new RenderCommandSystem();
  // 新建灯
  let gpu = new Gpu();

  // 生成将灯打开的命令
  let command = new Draw01Command(gpu);
  jjsSystem.setCommand(command);

  command = new Draw01Command(gpu);
  jjsSystem.setCommand(command);

  command = new Draw01Command(gpu);
  jjsSystem.setCommand(command);

  // 按下遥控器的开关执行这个命令
  jjsSystem.renderThisFrame(); // 这样就可以执行任何命令了

  /**
   * 在集成终端打开此文件
   *
   * ts-node 0428.ts
   *
   */
}
